#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""文档生成器组件"""

import os
import re
import logging
import inspect
from datetime import datetime
from typing import Dict, List, Optional, Tuple, Any, Union


class DocumentationGenerator:
    """文档生成器类"""
    
    def __init__(self, project_root: str = "."):
        """初始化文档生成器
        
        Args:
            project_root: 项目根目录
        """
        # 日志配置
        self.logger = logging.getLogger("DocumentationGenerator")
        
        # 项目根目录
        self.project_root = os.path.abspath(project_root)
        
        # 支持的文件类型
        self.supported_file_types = {
            ".py": self._parse_python_file,
            ".js": self._parse_javascript_file,
            ".html": self._parse_html_file,
            ".css": self._parse_css_file,
        }
        
        # 忽略的目录和文件
        self.ignore_patterns = [
            "__pycache__",
            ".git",
            ".venv",
            "venv",
            "node_modules",
            "dist",
            "build",
            "*.egg-info",
            ".pytest_cache",
            ".mypy_cache",
            "*.log",
            "*.tmp",
            "*.temp",
        ]
    
    def set_project_root(self, project_root: str) -> None:
        """设置项目根目录
        
        Args:
            project_root: 项目根目录
        """
        self.project_root = os.path.abspath(project_root)
        self.logger.info(f"已设置项目根目录: {self.project_root}")
    
    def add_ignore_pattern(self, pattern: str) -> None:
        """添加忽略模式
        
        Args:
            pattern: 忽略的模式
        """
        if pattern not in self.ignore_patterns:
            self.ignore_patterns.append(pattern)
            self.logger.info(f"已添加忽略模式: {pattern}")
    
    def remove_ignore_pattern(self, pattern: str) -> bool:
        """移除忽略模式
        
        Args:
            pattern: 忽略的模式
            
        Returns:
            bool: 是否成功移除
        """
        if pattern in self.ignore_patterns:
            self.ignore_patterns.remove(pattern)
            self.logger.info(f"已移除忽略模式: {pattern}")
            return True
        self.logger.warning(f"忽略模式不存在: {pattern}")
        return False
    
    def should_ignore(self, path: str) -> bool:
        """检查是否应该忽略指定路径
        
        Args:
            path: 要检查的路径
            
        Returns:
            bool: 是否应该忽略
        """
        # 转换为相对路径
        rel_path = os.path.relpath(path, self.project_root)
        
        # 检查是否匹配任何忽略模式
        for pattern in self.ignore_patterns:
            # 简单的模式匹配
            if pattern.startswith("*") and pattern.endswith("."):
                # 后缀匹配
                if rel_path.endswith(pattern[1:]):
                    return True
            elif pattern.startswith("*"):
                # 前缀匹配
                if rel_path.endswith(pattern[1:]):
                    return True
            elif pattern.endswith("*"):
                # 后缀匹配
                if rel_path.startswith(pattern[:-1]):
                    return True
            else:
                # 完全匹配或包含
                if pattern in rel_path or os.path.basename(rel_path) == pattern:
                    return True
        
        return False
    
    def generate_documentation(self, output_dir: str, format_type: str = "markdown") -> bool:
        """生成项目文档
        
        Args:
            output_dir: 输出目录
            format_type: 文档格式，支持 "markdown" 和 "html"
            
        Returns:
            bool: 是否成功生成
        """
        try:
            # 确保输出目录存在
            os.makedirs(output_dir, exist_ok=True)
            
            # 创建项目概览文档
            project_overview = self._generate_project_overview()
            
            # 生成文档
            if format_type.lower() == "markdown":
                self._generate_markdown_documentation(project_overview, output_dir)
            elif format_type.lower() == "html":
                self._generate_html_documentation(project_overview, output_dir)
            else:
                self.logger.error(f"不支持的文档格式: {format_type}")
                return False
            
            self.logger.info(f"文档已成功生成到: {output_dir}")
            return True
        except Exception as e:
            self.logger.error(f"生成文档失败: {str(e)}")
            return False
    
    def _generate_project_overview(self) -> Dict[str, Any]:
        """生成项目概览信息
        
        Returns:
            Dict[str, Any]: 项目概览信息
        """
        # 初始化项目信息
        project_info = {
            "name": os.path.basename(self.project_root),
            "root_path": self.project_root,
            "creation_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "modules": {},
            "total_files": 0,
            "total_lines": 0,
            "total_classes": 0,
            "total_functions": 0,
        }
        
        # 遍历项目目录
        for root, dirs, files in os.walk(self.project_root):
            # 过滤目录
            dirs[:] = [d for d in dirs if not self.should_ignore(os.path.join(root, d))]
            
            # 处理文件
            for file in files:
                file_path = os.path.join(root, file)
                
                # 检查是否应该忽略文件
                if self.should_ignore(file_path):
                    continue
                
                # 获取文件扩展名
                _, ext = os.path.splitext(file)
                
                # 检查是否支持该文件类型
                if ext in self.supported_file_types:
                    # 解析文件
                    parser = self.supported_file_types[ext]
                    file_info = parser(file_path)
                    
                    # 更新统计信息
                    project_info["total_files"] += 1
                    project_info["total_lines"] += file_info.get("line_count", 0)
                    project_info["total_classes"] += len(file_info.get("classes", []))
                    project_info["total_functions"] += len(file_info.get("functions", []))
                    
                    # 添加到模块信息
                    module_path = os.path.relpath(root, self.project_root)
                    if module_path == ".":
                        module_path = "root"
                    
                    if module_path not in project_info["modules"]:
                        project_info["modules"][module_path] = []
                    
                    project_info["modules"][module_path].append(file_info)
        
        return project_info
    
    def _parse_python_file(self, file_path: str) -> Dict[str, Any]:
        """解析Python文件
        
        Args:
            file_path: 文件路径
            
        Returns:
            Dict[str, Any]: 文件信息
        """
        try:
            # 读取文件内容
            with open(file_path, "r", encoding="utf-8") as f:
                content = f.read()
            
            # 初始化文件信息
            file_info = {
                "name": os.path.basename(file_path),
                "path": os.path.relpath(file_path, self.project_root),
                "type": "python",
                "line_count": len(content.splitlines()),
                "docstring": self._extract_docstring(content),
                "imports": self._extract_imports(content),
                "classes": [],
                "functions": [],
            }
            
            # 提取类信息
            class_pattern = re.compile(r"class\s+(\w+)(?:\(([^)]*)\))?:\s*(?:"""([\s\S]*?)"""|'''([\s\S]*?)'''|.*?)(?=\n\s*def\s|\n\s*class\s|\n\s*@|\n\s*#|\n\s*$)")
            for match in class_pattern.finditer(content):
                class_name = match.group(1)
                class_bases = match.group(2) or ""
                class_docstring = match.group(3) or match.group(4) or ""
                
                # 提取类中的方法
                class_start = match.end()
                class_end = self._find_class_end(content, class_start)
                class_content = content[class_start:class_end]
                
                # 提取类方法
                methods = []
                method_pattern = re.compile(r"\s*def\s+(\w+)(\([^)]*\)):\s*(?:"""([\s\S]*?)"""|'''([\s\S]*?)'''|.*?)(?=\n\s*def\s|\n\s*class\s|\n\s*@|\n\s*#|\n\s*$)")
                for method_match in method_pattern.finditer(class_content):
                    method_name = method_match.group(1)
                    method_params = method_match.group(2)
                    method_docstring = method_match.group(3) or method_match.group(4) or ""
                    
                    methods.append({
                        "name": method_name,
                        "params": method_params,
                        "docstring": method_docstring.strip(),
                    })
                
                file_info["classes"].append({
                    "name": class_name,
                    "bases": class_bases,
                    "docstring": class_docstring.strip(),
                    "methods": methods,
                })
            
            # 提取函数信息（不包括类中的方法）
            function_pattern = re.compile(r"^\s*(?:@\w+(?:\([^)]*\))?\s*)*def\s+(\w+)(\([^)]*\)):\s*(?:"""([\s\S]*?)"""|'''([\s\S]*?)'''|.*?)(?=\n\s*def\s|\n\s*class\s|\n\s*@|\n\s*#|\n\s*$)", re.MULTILINE)
            for match in function_pattern.finditer(content):
                # 检查函数是否在类中
                function_start = match.start()
                in_class = False
                for class_match in class_pattern.finditer(content):
                    class_start = class_match.start()
                    class_end = self._find_class_end(content, class_match.end())
                    if class_start < function_start < class_end:
                        in_class = True
                        break
                
                # 如果不在类中，添加到函数列表
                if not in_class:
                    function_name = match.group(1)
                    function_params = match.group(2)
                    function_docstring = match.group(3) or match.group(4) or ""
                    
                    file_info["functions"].append({
                        "name": function_name,
                        "params": function_params,
                        "docstring": function_docstring.strip(),
                    })
            
            return file_info
        except Exception as e:
            self.logger.error(f"解析Python文件失败 {file_path}: {str(e)}")
            return {
                "name": os.path.basename(file_path),
                "path": os.path.relpath(file_path, self.project_root),
                "type": "python",
                "error": str(e),
            }
    
    def _find_class_end(self, content: str, start_pos: int) -> int:
        """查找类的结束位置
        
        Args:
            content: 文件内容
            start_pos: 开始位置
            
        Returns:
            int: 结束位置
        """
        # 简单的缩进检测
        lines = content[start_pos:].splitlines()
        if not lines:
            return start_pos
        
        # 获取第一行的缩进
        first_line = lines[0]
        indent = len(first_line) - len(first_line.lstrip())
        
        # 查找缩进小于等于类体缩进的行
        for i, line in enumerate(lines):
            stripped_line = line.lstrip()
            # 跳过空行和注释
            if not stripped_line or stripped_line.startswith("#"):
                continue
            
            # 检查缩进
            current_indent = len(line) - len(stripped_line)
            if current_indent <= indent:
                return start_pos + sum(len(line) + 1 for line in lines[:i])
        
        # 如果没有找到，返回文件结尾
        return len(content)
    
    def _extract_docstring(self, content: str) -> str:
        """提取文件的文档字符串
        
        Args:
            content: 文件内容
            
        Returns:
            str: 文档字符串
        """
        # 查找文档字符串模式
        pattern = re.compile(r"^\s*(?:"""([\s\S]*?)"""|'''([\s\S]*?)''')", re.MULTILINE)
        match = pattern.search(content)
        
        if match:
            return (match.group(1) or match.group(2) or "").strip()
        
        return ""
    
    def _extract_imports(self, content: str) -> List[str]:
        """提取导入的模块
        
        Args:
            content: 文件内容
            
        Returns:
            List[str]: 导入的模块列表
        """
        imports = []
        
        # 查找import语句
        import_pattern = re.compile(r"^\s*import\s+(\w+(?:\.\w+)*)", re.MULTILINE)
        for match in import_pattern.finditer(content):
            imports.append(match.group(1))
        
        # 查找from...import语句
        from_import_pattern = re.compile(r"^\s*from\s+(\w+(?:\.\w+)*)\s+import", re.MULTILINE)
        for match in from_import_pattern.finditer(content):
            imports.append(match.group(1))
        
        return imports
    
    def _parse_javascript_file(self, file_path: str) -> Dict[str, Any]:
        """解析JavaScript文件
        
        Args:
            file_path: 文件路径
            
        Returns:
            Dict[str, Any]: 文件信息
        """
        try:
            # 读取文件内容
            with open(file_path, "r", encoding="utf-8") as f:
                content = f.read()
            
            # 初始化文件信息
            file_info = {
                "name": os.path.basename(file_path),
                "path": os.path.relpath(file_path, self.project_root),
                "type": "javascript",
                "line_count": len(content.splitlines()),
                "docstring": self._extract_javascript_docstring(content),
                "imports": self._extract_javascript_imports(content),
                "classes": [],
                "functions": [],
            }
            
            # 提取类信息
            class_pattern = re.compile(r"class\s+(\w+)(?:\s+extends\s+(\w+))?\s*{([\s\S]*?)}")
            for match in class_pattern.finditer(content):
                class_name = match.group(1)
                class_extends = match.group(2) or ""
                class_content = match.group(3)
                
                # 提取类文档字符串
                class_docstring = self._extract_javascript_docstring(class_content)
                
                # 提取类方法
                methods = []
                method_pattern = re.compile(r"(\w+)\s*\(([^)]*)\)\s*{(?:/\*\*([\s\S]*?)\*/)?([\s\S]*?)(?=\}\s*\w+\s*\(|\}\s*\}|$)")
                for method_match in method_pattern.finditer(class_content):
                    method_name = method_match.group(1)
                    method_params = method_match.group(2)
                    method_docstring = method_match.group(3) or ""
                    
                    methods.append({
                        "name": method_name,
                        "params": method_params,
                        "docstring": method_docstring.strip(),
                    })
                
                file_info["classes"].append({
                    "name": class_name,
                    "extends": class_extends,
                    "docstring": class_docstring,
                    "methods": methods,
                })
            
            # 提取函数信息
            function_pattern = re.compile(r"function\s+(\w+)\s*\(([^)]*)\)\s*{(?:/\*\*([\s\S]*?)\*/)?([\s\S]*?)}\s*(?=function\s|class\s|$)")
            for match in function_pattern.finditer(content):
                function_name = match.group(1)
                function_params = match.group(2)
                function_docstring = match.group(3) or ""
                
                file_info["functions"].append({
                    "name": function_name,
                    "params": function_params,
                    "docstring": function_docstring.strip(),
                })
            
            # 提取箭头函数
            arrow_function_pattern = re.compile(r"const\s+(\w+)\s*=\s*\(([^)]*)\)\s*=>\s*{([\s\S]*?)};\s*(?=const\s|function\s|class\s|$)")
            for match in arrow_function_pattern.finditer(content):
                function_name = match.group(1)
                function_params = match.group(2)
                function_body = match.group(3)
                
                file_info["functions"].append({
                    "name": function_name,
                    "params": function_params,
                    "docstring": "",
                    "is_arrow": True,
                })
            
            return file_info
        except Exception as e:
            self.logger.error(f"解析JavaScript文件失败 {file_path}: {str(e)}")
            return {
                "name": os.path.basename(file_path),
                "path": os.path.relpath(file_path, self.project_root),
                "type": "javascript",
                "error": str(e),
            }
    
    def _extract_javascript_docstring(self, content: str) -> str:
        """提取JavaScript的文档字符串
        
        Args:
            content: 文件内容
            
        Returns:
            str: 文档字符串
        """
        # 查找JSDoc注释
        pattern = re.compile(r"/\*\*([\s\S]*?)\*/")
        match = pattern.search(content)
        
        if match:
            # 移除每行的星号
            lines = match.group(1).splitlines()
            cleaned_lines = []
            for line in lines:
                cleaned_line = line.lstrip().lstrip('*').lstrip()
                if cleaned_line:
                    cleaned_lines.append(cleaned_line)
            
            return '\n'.join(cleaned_lines)
        
        return ""
    
    def _extract_javascript_imports(self, content: str) -> List[str]:
        """提取JavaScript导入的模块
        
        Args:
            content: 文件内容
            
        Returns:
            List[str]: 导入的模块列表
        """
        imports = []
        
        # 查找import语句
        import_pattern = re.compile(r"import\s+(?:.*?)\s+from\s+['"](.*?)['"]")
        for match in import_pattern.finditer(content):
            imports.append(match.group(1))
        
        # 查找require语句
        require_pattern = re.compile(r"require\(['"](.*?)['"]\)")
        for match in require_pattern.finditer(content):
            imports.append(match.group(1))
        
        return imports
    
    def _parse_html_file(self, file_path: str) -> Dict[str, Any]:
        """解析HTML文件
        
        Args:
            file_path: 文件路径
            
        Returns:
            Dict[str, Any]: 文件信息
        """
        try:
            # 读取文件内容
            with open(file_path, "r", encoding="utf-8") as f:
                content = f.read()
            
            # 初始化文件信息
            file_info = {
                "name": os.path.basename(file_path),
                "path": os.path.relpath(file_path, self.project_root),
                "type": "html",
                "line_count": len(content.splitlines()),
                "title": self._extract_html_title(content),
                "headings": self._extract_html_headings(content),
                "links": self._extract_html_links(content),
                "scripts": self._extract_html_scripts(content),
                "styles": self._extract_html_styles(content),
            }
            
            return file_info
        except Exception as e:
            self.logger.error(f"解析HTML文件失败 {file_path}: {str(e)}")
            return {
                "name": os.path.basename(file_path),
                "path": os.path.relpath(file_path, self.project_root),
                "type": "html",
                "error": str(e),
            }
    
    def _extract_html_title(self, content: str) -> str:
        """提取HTML标题
        
        Args:
            content: 文件内容
            
        Returns:
            str: 标题
        """
        pattern = re.compile(r"<title>(.*?)</title>", re.IGNORECASE)
        match = pattern.search(content)
        
        if match:
            return match.group(1)
        
        return ""
    
    def _extract_html_headings(self, content: str) -> List[Tuple[str, str]]:
        """提取HTML标题标签
        
        Args:
            content: 文件内容
            
        Returns:
            List[Tuple[str, str]]: 标题标签列表，每个元素是 (级别, 文本)
        """
        headings = []
        
        # 查找h1-h6标签
        for level in range(1, 7):
            pattern = re.compile(rf"<h{level}>(.*?)</h{level}>", re.IGNORECASE)
            for match in pattern.finditer(content):
                headings.append((f"h{level}", match.group(1)))
        
        return headings
    
    def _extract_html_links(self, content: str) -> List[Tuple[str, str]]:
        """提取HTML链接
        
        Args:
            content: 文件内容
            
        Returns:
            List[Tuple[str, str]]: 链接列表，每个元素是 (文本, URL)
        """
        links = []
        
        # 查找a标签
        pattern = re.compile(r"<a\s+[^>]*href=["'](.*?)["'][^>]*>(.*?)</a>", re.IGNORECASE)
        for match in pattern.finditer(content):
            url = match.group(1)
            text = match.group(2)
            links.append((text, url))
        
        return links
    
    def _extract_html_scripts(self, content: str) -> List[str]:
        """提取HTML中的脚本
        
        Args:
            content: 文件内容
            
        Returns:
            List[str]: 脚本URL列表
        """
        scripts = []
        
        # 查找script标签
        pattern = re.compile(r"<script\s+[^>]*src=["'](.*?)["'][^>]*>", re.IGNORECASE)
        for match in pattern.finditer(content):
            scripts.append(match.group(1))
        
        return scripts
    
    def _extract_html_styles(self, content: str) -> List[str]:
        """提取HTML中的样式
        
        Args:
            content: 文件内容
            
        Returns:
            List[str]: 样式URL列表
        """
        styles = []
        
        # 查找link标签（样式表）
        pattern = re.compile(r"<link\s+[^>]*rel=["']stylesheet["'][^>]*href=["'](.*?)["'][^>]*>", re.IGNORECASE)
        for match in pattern.finditer(content):
            styles.append(match.group(1))
        
        return styles
    
    def _parse_css_file(self, file_path: str) -> Dict[str, Any]:
        """解析CSS文件
        
        Args:
            file_path: 文件路径
            
        Returns:
            Dict[str, Any]: 文件信息
        """
        try:
            # 读取文件内容
            with open(file_path, "r", encoding="utf-8") as f:
                content = f.read()
            
            # 初始化文件信息
            file_info = {
                "name": os.path.basename(file_path),
                "path": os.path.relpath(file_path, self.project_root),
                "type": "css",
                "line_count": len(content.splitlines()),
                "selectors": self._extract_css_selectors(content),
                "rules_count": self._count_css_rules(content),
            }
            
            return file_info
        except Exception as e:
            self.logger.error(f"解析CSS文件失败 {file_path}: {str(e)}")
            return {
                "name": os.path.basename(file_path),
                "path": os.path.relpath(file_path, self.project_root),
                "type": "css",
                "error": str(e),
            }
    
    def _extract_css_selectors(self, content: str) -> List[str]:
        """提取CSS选择器
        
        Args:
            content: 文件内容
            
        Returns:
            List[str]: 选择器列表
        """
        selectors = []
        
        # 移除注释
        content = re.sub(r"/\*[\s\S]*?\*/", "", content)
        
        # 查找选择器
        pattern = re.compile(r"([^{]+){[^}]*}")
        for match in pattern.finditer(content):
            selector_text = match.group(1).strip()
            # 分割多个选择器
            for selector in selector_text.split(","):
                selector = selector.strip()
                if selector and selector not in selectors:
                    selectors.append(selector)
        
        return selectors
    
    def _count_css_rules(self, content: str) -> int:
        """计算CSS规则数量
        
        Args:
            content: 文件内容
            
        Returns:
            int: 规则数量
        """
        # 移除注释
        content = re.sub(r"/\*[\s\S]*?\*/", "", content)
        
        # 查找规则
        pattern = re.compile(r"[^{]+{[^}]*}")
        return len(pattern.findall(content))
    
    def _generate_markdown_documentation(self, project_overview: Dict[str, Any], output_dir: str) -> None:
        """生成Markdown格式的文档
        
        Args:
            project_overview: 项目概览信息
            output_dir: 输出目录
        """
        # 创建README.md文件
        readme_path = os.path.join(output_dir, "README.md")
        with open(readme_path, "w", encoding="utf-8") as f:
            # 写入项目标题
            f.write(f"# {project_overview['name']} 项目文档\n\n")
            
            # 写入项目信息
            f.write("## 项目信息\n\n")
            f.write(f"- **项目名称**: {project_overview['name']}\n")
            f.write(f"- **项目路径**: {project_overview['root_path']}\n")
            f.write(f"- **文档生成时间**: {project_overview['creation_time']}\n\n")
            
            # 写入项目统计
            f.write("## 项目统计\n\n")
            f.write(f"- **文件总数**: {project_overview['total_files']}\n")
            f.write(f"- **代码总行数**: {project_overview['total_lines']}\n")
            f.write(f"- **类总数**: {project_overview['total_classes']}\n")
            f.write(f"- **函数总数**: {project_overview['total_functions']}\n\n")
            
            # 写入模块列表
            f.write("## 模块列表\n\n")
            
            # 创建模块目录
            modules_dir = os.path.join(output_dir, "modules")
            os.makedirs(modules_dir, exist_ok=True)
            
            # 遍历模块
            for module_path, files in project_overview["modules"].items():
                # 写入模块链接
                module_name = module_path.replace("/", "_")
                module_file = f"{module_name}.md"
                f.write(f"- [{module_path}](modules/{module_file})\n")
                
                # 创建模块文档
                module_doc_path = os.path.join(modules_dir, module_file)
                self._generate_module_markdown(files, module_doc_path, module_path)
            
            # 写入忽略的文件
            if self.ignore_patterns:
                f.write("\n## 忽略的文件\n\n")
                f.write("以下文件和目录未包含在文档中:\n\n")
                for pattern in self.ignore_patterns:
                    f.write(f"- `{pattern}`\n")
    
    def _generate_module_markdown(self, files: List[Dict[str, Any]], output_path: str, module_path: str) -> None:
        """生成模块的Markdown文档
        
        Args:
            files: 文件信息列表
            output_path: 输出路径
            module_path: 模块路径
        """
        with open(output_path, "w", encoding="utf-8") as f:
            # 写入模块标题
            f.write(f"# {module_path} 模块\n\n")
            
            # 遍历文件
            for file_info in files:
                # 写入文件标题
                f.write(f"## {file_info['name']}\n\n")
                
                # 写入文件信息
                f.write(f"**文件路径**: {file_info['path']}\n\n")
                f.write(f"**文件类型**: {file_info['type']}\n\n")
                f.write(f"**代码行数**: {file_info.get('line_count', 0)}\n\n")
                
                # 写入文档字符串
                docstring = file_info.get('docstring', '')
                if docstring:
                    f.write("### 文档说明\n\n")
                    f.write(f"{docstring}\n\n")
                
                # 写入导入模块
                imports = file_info.get('imports', [])
                if imports:
                    f.write("### 导入模块\n\n")
                    for imp in imports:
                        f.write(f"- `{imp}`\n")
                    f.write("\n")
                
                # 写入类信息
                classes = file_info.get('classes', [])
                if classes:
                    f.write("### 类\n\n")
                    for cls in classes:
                        f.write(f"#### {cls['name']}\n\n")
                        
                        # 写入类继承信息
                        if cls.get('bases'):
                            f.write(f"**继承**: {cls['bases']}\n\n")
                        elif cls.get('extends'):
                            f.write(f"**继承**: {cls['extends']}\n\n")
                        
                        # 写入类文档
                        if cls.get('docstring'):
                            f.write(f"{cls['docstring']}\n\n")
                        
                        # 写入类方法
                        methods = cls.get('methods', [])
                        if methods:
                            f.write("##### 方法\n\n")
                            for method in methods:
                                f.write(f"- **{method['name']}{method['params']}**\n")
                                if method.get('docstring'):
                                    f.write(f"  \n{method['docstring']}\n\n")
                
                # 写入函数信息
                functions = file_info.get('functions', [])
                if functions:
                    f.write("### 函数\n\n")
                    for func in functions:
                        f.write(f"#### {func['name']}{func['params']}\n\n")
                        if func.get('docstring'):
                            f.write(f"{func['docstring']}\n\n")
                        if func.get('is_arrow'):
                            f.write("**类型**: 箭头函数\n\n")
                
                # 写入HTML特定信息
                if file_info.get('type') == 'html':
                    if file_info.get('title'):
                        f.write(f"**页面标题**: {file_info['title']}\n\n")
                    
                    headings = file_info.get('headings', [])
                    if headings:
                        f.write("### 页面标题结构\n\n")
                        for level, text in headings:
                            indent = "  " * (int(level[1]) - 1)
                            f.write(f"{indent}- **{level}**: {text}\n")
                        f.write("\n")
                
                # 写入错误信息
                if file_info.get('error'):
                    f.write(f"### 解析错误\n\n")
                    f.write(f"{file_info['error']}\n\n")
                
                f.write("---\n\n")
    
    def _generate_html_documentation(self, project_overview: Dict[str, Any], output_dir: str) -> None:
        """生成HTML格式的文档
        
        Args:
            project_overview: 项目概览信息
            output_dir: 输出目录
        """
        # 创建index.html文件
        index_path = os.path.join(output_dir, "index.html")
        
        # 生成HTML内容
        html_content = self._generate_html_content(project_overview, output_dir)
        
        # 写入文件
        with open(index_path, "w", encoding="utf-8") as f:
            f.write(html_content)
        
        # 复制静态资源
        self._copy_static_resources(output_dir)
    
    def _generate_html_content(self, project_overview: Dict[str, Any], output_dir: str) -> str:
        """生成HTML内容
        
        Args:
            project_overview: 项目概览信息
            output_dir: 输出目录
            
        Returns:
            str: HTML内容
        """
        # 生成HTML模板
        html_template = """
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{project_name} - 项目文档</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="container">
        <header>
            <h1>{project_name} 项目文档</h1>
            <p>生成时间: {creation_time}</p>
        </header>
        
        <section id="project-info">
            <h2>项目信息</h2>
            <ul>
                <li><strong>项目名称:</strong> {project_name}</li>
                <li><strong>项目路径:</strong> {project_path}</li>
                <li><strong>文件总数:</strong> {total_files}</li>
                <li><strong>代码总行数:</strong> {total_lines}</li>
                <li><strong>类总数:</strong> {total_classes}</li>
                <li><strong>函数总数:</strong> {total_functions}</li>
            </ul>
        </section>
        
        <section id="modules">
            <h2>模块列表</h2>
            <div class="module-list">
                {module_list}
            </div>
        </section>
        
        <footer>
            <p>&copy; {year} {project_name} 文档生成器</p>
        </footer>
    </div>
</body>
</html>
        """
        
        # 生成模块列表
        module_list_html = ""
        
        # 创建模块目录
        modules_dir = os.path.join(output_dir, "modules")
        os.makedirs(modules_dir, exist_ok=True)
        
        # 遍历模块
        for module_path, files in project_overview["modules"].items():
            module_name = module_path.replace("/", "_")
            module_file = f"modules/{module_name}.html"
            
            # 生成模块链接
            module_list_html += f"<div class='module-item'><a href='{module_file}'>{module_path}</a></div>"
            
            # 创建模块HTML文件
            module_html_path = os.path.join(modules_dir, module_name + ".html")
            self._generate_module_html(files, module_html_path, module_path, project_overview["name"])
        
        # 替换模板变量
        html_content = html_template.format(
            project_name=project_overview["name"],
            creation_time=project_overview["creation_time"],
            project_path=project_overview["root_path"],
            total_files=project_overview["total_files"],
            total_lines=project_overview["total_lines"],
            total_classes=project_overview["total_classes"],
            total_functions=project_overview["total_functions"],
            module_list=module_list_html,
            year=datetime.now().year,
        )
        
        return html_content
    
    def _generate_module_html(self, files: List[Dict[str, Any]], output_path: str, module_path: str, project_name: str) -> None:
        """生成模块的HTML文档
        
        Args:
            files: 文件信息列表
            output_path: 输出路径
            module_path: 模块路径
            project_name: 项目名称
        """
        # 生成HTML模板
        html_template = """
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{module_path} - {project_name} 文档</title>
    <link rel="stylesheet" href="../styles.css">
</head>
<body>
    <div class="container">
        <header>
            <h1>{module_path} 模块</h1>
            <nav><a href="../index.html">返回首页</a></nav>
        </header>
        
        <section id="files">
            {file_contents}
        </section>
        
        <footer>
            <p>&copy; {year} {project_name} 文档生成器</p>
        </footer>
    </div>
</body>
</html>
        """
        
        # 生成文件内容
        file_contents = ""
        for file_info in files:
            file_content_html = self._generate_file_html(file_info)
            file_contents += file_content_html
        
        # 替换模板变量
        html_content = html_template.format(
            module_path=module_path,
            project_name=project_name,
            file_contents=file_contents,
            year=datetime.now().year,
        )
        
        # 写入文件
        with open(output_path, "w", encoding="utf-8") as f:
            f.write(html_content)
    
    def _generate_file_html(self, file_info: Dict[str, Any]) -> str:
        """生成文件的HTML内容
        
        Args:
            file_info: 文件信息
            
        Returns:
            str: HTML内容
        """
        # 生成文件内容模板
        file_template = """
<div class="file">
    <h2>{file_name}</h2>
    
    <div class="file-info">
        <p><strong>文件路径:</strong> {file_path}</p>
        <p><strong>文件类型:</strong> {file_type}</p>
        <p><strong>代码行数:</strong> {line_count}</p>
    </div>
    
    {docstring_section}
    {imports_section}
    {classes_section}
    {functions_section}
    {html_specific_section}
    {error_section}
</div>
        """
        
        # 生成文档字符串部分
        docstring = file_info.get('docstring', '')
        docstring_section = """
    <div class="docstring">
        <h3>文档说明</h3>
        <div class="docstring-content">{docstring}</div>
    </div>""" if docstring else ""
    
        # 生成导入模块部分
        imports = file_info.get('imports', [])
        imports_section = """
    <div class="imports">
        <h3>导入模块</h3>
        <ul>{imports_list}</ul>
    </div>""" if imports else ""
        
        imports_list = ""
        if imports:
            for imp in imports:
                imports_list += f"<li>{imp}</li>"
        
        # 生成类部分
        classes = file_info.get('classes', [])
        classes_section = """
    <div class="classes">
        <h3>类</h3>
        <div class="classes-content">{classes_content}</div>
    </div>""" if classes else ""
        
        classes_content = ""
        if classes:
            for cls in classes:
                # 生成类继承信息
                inheritance = ""
                if cls.get('bases'):
                    inheritance = f"<p><strong>继承:</strong> {cls['bases']}</p>"
                elif cls.get('extends'):
                    inheritance = f"<p><strong>继承:</strong> {cls['extends']}</p>"
                
                # 生成类文档
                class_docstring = ""
                if cls.get('docstring'):
                    class_docstring = f"<div class="class-docstring">{cls['docstring']}</div>"
                
                # 生成类方法
                methods = cls.get('methods', [])
                methods_section = ""
                if methods:
                    methods_section = "<div class="methods"><h4>方法</h4><ul>"
                    for method in methods:
                        method_docstring = ""
                        if method.get('docstring'):
                            method_docstring = f"<div class="method-docstring">{method['docstring']}</div>"
                        
                        methods_section += f"<li><strong>{method['name']}{method['params']}</strong>{method_docstring}</li>"
                    methods_section += "</ul></div>"
                
                classes_content += f"<div class="class-item"><h4>{cls['name']}</h4>{inheritance}{class_docstring}{methods_section}</div>"
    
        # 生成函数部分
        functions = file_info.get('functions', [])
        functions_section = """
    <div class="functions">
        <h3>函数</h3>
        <div class="functions-content">{functions_content}</div>
    </div>""" if functions else ""
        
        functions_content = ""
        if functions:
            for func in functions:
                func_docstring = ""
                if func.get('docstring'):
                    func_docstring = f"<div class="func-docstring">{func['docstring']}</div>"
                
                func_type = ""
                if func.get('is_arrow'):
                    func_type = "<p><strong>类型:</strong> 箭头函数</p>"
                
                functions_content += f"<div class="function-item"><h4>{func['name']}{func['params']}</h4>{func_docstring}{func_type}</div>"
    
        # 生成HTML特定部分
        html_specific_section = ""
        if file_info.get('type') == 'html':
            html_specific_section = "<div class="html-specific"><h3>页面信息</h3>"
            
            if file_info.get('title'):
                html_specific_section += f"<p><strong>页面标题:</strong> {file_info['title']}</p>"
            
            headings = file_info.get('headings', [])
            if headings:
                html_specific_section += "<h4>页面标题结构</h4><ul>"
                for level, text in headings:
                    indent = "&nbsp;&nbsp;" * (int(level[1]) - 1)
                    html_specific_section += f"<li>{indent}<strong>{level}:</strong> {text}</li>"
                html_specific_section += "</ul>"
            
            html_specific_section += "</div>"
    
        # 生成错误部分
        error_section = """
    <div class="error">
        <h3>解析错误</h3>
        <p>{error}</p>
    </div>""" if file_info.get('error') else ""
    
        # 替换模板变量
        file_html = file_template.format(
            file_name=file_info['name'],
            file_path=file_info['path'],
            file_type=file_info['type'],
            line_count=file_info.get('line_count', 0),
            docstring_section=docstring_section,
            imports_section=imports_section,
            imports_list=imports_list,
            classes_section=classes_section,
            classes_content=classes_content,
            functions_section=functions_section,
            functions_content=functions_content,
            html_specific_section=html_specific_section,
            error_section=error_section,
        )
        
        return file_html
    
    def _copy_static_resources(self, output_dir: str) -> None:
        """复制静态资源
        
        Args:
            output_dir: 输出目录
        """
        # 创建样式文件
        styles_path = os.path.join(output_dir, "styles.css")
        
        # 样式内容
        styles_content = """
/* 基础样式 */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
        'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
        sans-serif;
    line-height: 1.6;
    color: #333;
    background-color: #f5f5f5;
}

.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
    background-color: #fff;
    min-height: 100vh;
}

/* 标题样式 */
header {
    margin-bottom: 30px;
    padding-bottom: 20px;
    border-bottom: 1px solid #eaeaea;
}

header h1 {
    font-size: 2.5em;
    color: #2c3e50;
    margin-bottom: 10px;
}

header p {
    color: #7f8c8d;
}

header nav {
    margin-top: 15px;
}

header nav a {
    color: #3498db;
    text-decoration: none;
}

header nav a:hover {
    text-decoration: underline;
}

/* 章节样式 */
section {
    margin-bottom: 40px;
}

section h2 {
    font-size: 1.8em;
    color: #2c3e50;
    margin-bottom: 20px;
    padding-bottom: 10px;
    border-bottom: 1px solid #eaeaea;
}

section h3 {
    font-size: 1.4em;
    color: #34495e;
    margin: 25px 0 15px 0;
}

section h4 {
    font-size: 1.2em;
    color: #34495e;
    margin: 20px 0 10px 0;
}

/* 列表样式 */
ul, ol {
    margin-left: 25px;
    margin-bottom: 20px;
}

li {
    margin-bottom: 8px;
}

/* 模块列表样式 */
.module-list {
    display: flex;
    flex-wrap: wrap;
    gap: 15px;
}

.module-item {
    background-color: #ecf0f1;
    padding: 15px;
    border-radius: 5px;
    flex: 1 1 300px;
}

.module-item a {
    color: #3498db;
    text-decoration: none;
    font-weight: bold;
}

.module-item a:hover {
    text-decoration: underline;
}

/* 文件样式 */
.file {
    margin-bottom: 40px;
    padding: 20px;
    background-color: #f9f9f9;
    border-radius: 5px;
}

.file h2 {
    font-size: 1.6em;
    color: #2c3e50;
    margin-bottom: 15px;
    border-bottom: 1px solid #eaeaea;
    padding-bottom: 10px;
}

.file-info {
    background-color: #ecf0f1;
    padding: 15px;
    border-radius: 5px;
    margin-bottom: 20px;
}

.file-info p {
    margin-bottom: 8px;
}

/* 文档字符串样式 */
.docstring-content,
.class-docstring,
.method-docstring,
.func-docstring {
    background-color: #f1f1f1;
    padding: 15px;
    border-radius: 5px;
    margin: 10px 0;
    font-family: 'Courier New', Courier, monospace;
    white-space: pre-wrap;
}

/* 类和函数样式 */
.class-item,
.function-item {
    margin-bottom: 25px;
    padding: 15px;
    background-color: #f5f5f5;
    border-radius: 5px;
}

.methods {
    margin-top: 15px;
    padding-left: 20px;
}

/* 错误样式 */
.error {
    background-color: #fee;
    padding: 15px;
    border-radius: 5px;
    border-left: 4px solid #f44336;
}

/* 页脚样式 */
footer {
    margin-top: 50px;
    padding-top: 20px;
    border-top: 1px solid #eaeaea;
    text-align: center;
    color: #7f8c8d;
}

/* 响应式设计 */
@media (max-width: 768px) {
    .container {
        padding: 15px;
    }
    
    header h1 {
        font-size: 2em;
    }
    
    section h2 {
        font-size: 1.5em;
    }
    
    .module-item {
        flex: 1 1 100%;
    }
}
        """
        
        # 写入样式文件
        with open(styles_path, "w", encoding="utf-8") as f:
            f.write(styles_content)